/* TabView.cpp
Michael Zahniser, 01/08/09

Function definitions for the TabView class.
*/

#include "TabView.h"

#include "Interface.h"
#include "EmbeddedFont.h"



TabView::TabView(int height)
	: active(tabs.end()),
	height(height > 0 ? height : -height), bottom(height > 0 ? height : 0)
{
	font.Load(EmbeddedFont::DATA, EmbeddedFont::WIDTH, EmbeddedFont::HEIGHT);
	greyFont.Load(EmbeddedFont::DATA, EmbeddedFont::WIDTH, EmbeddedFont::HEIGHT);
	greyFont.SetColor(160, 160, 160);
}



void TabView::Add(const string &name, View *view, Interface *gui)
{
	tabs.push_back(Tab(name, view));
	active = --tabs.end();
	if(gui)
	{
		gui->Add(view, 0, bottom, 0, -height);
		gui->OnRemove(view, this);
	}
	ActivateView(gui);
}



// Set the color of the tab corresponding to the given view.
void TabView::SetColor(View *view, int red, int green, int blue)
{
	for(list<Tab>::iterator it = tabs.begin(); it != tabs.end(); ++it)
		if(it->view == view)
			it->SetColor(red, green, blue);
}



// Callback function for when a View is removed from the interface:
void TabView::operator()(const View *view)
{
	for(list<Tab>::iterator it = tabs.begin(); it != tabs.end(); ++it)
		if(it->view == view)
		{
			it = tabs.erase(it);
			if(it != tabs.begin())
			{
				// Unless the list is now empty, activate the previous view.
				--it;
				active = it;
				ActivateView();
			}
		}
}



// Initialize a view, given the command line arguments for the program.
// If the view cannot be initialized, this function should return false.
// NOTE: SDL may not be initialized yet when a View's constructor is called,
// so all initialization using SDL should be done here instead.
bool TabView::Initialize(const Surface &surface)
{
	ActivateView();
	return true;
}



// Handle an event. If the event involves (x, y) coordinates, they have been
// translated such that (0, 0) is the top left corner of this View.
// This function should return false if this view does not support the given
// event and wants other views to have a chance to handle it.
bool TabView::Handle(const SDL_Event &event)
{
	if(event.type == SDL_MOUSEBUTTONUP)
	{
		if(event.button.button != 1)
			return false;

		for(list<Tab>::iterator it = tabs.begin(); it != tabs.end(); ++it)
			if(it->endX > event.button.x)
			{
				active = it;
				break;
			}
	}
	else if(event.type == SDL_KEYDOWN && (event.key.keysym.mod & (KMOD_CTRL | KMOD_META)))
	{
		SDLKey key = event.key.keysym.sym;
		if(key == SDLK_LEFT)
		{
			if(active == tabs.begin())
				active = tabs.end();
			--active;
		}
		else if(key == SDLK_RIGHT)
		{
			++active;
			if(active == tabs.end())
				active = tabs.begin();
		}
		else
			return false;
	}
	else
		return false;

	ActivateView();
	return true;
}



// Draw the view in the given surface. The surface is passed as a (shallow)
// copy so that it is impossible for derived classes to modify View::surface
// to point to anything other than what Interface assigns to it.
void TabView::Draw(Surface surface) const
{
	static const int PAD = 8;
	int x = 0;
	int y = (surface.Height() - font.Height()) / 2;

	for(list<Tab>::iterator it = tabs.begin(); it != tabs.end(); ++it)
	{
		int width = font.Width(it->name) + 2 * PAD;
		if(it == active)
		{
			surface.FillRect(x, 0, width, surface.Height(), surface.Color(it->red, it->green, it->blue));

			font.Draw(it->name, surface, x + PAD, y);
		}
		else
		{
			surface.FillRect(x, 0, width, surface.Height() - 1, surface.Color(it->red / 4 + 184, it->green / 4 + 184, it->blue / 4 + 184));

			greyFont.Draw(it->name, surface, x + PAD, y);
			surface.HLine(x, 0, width, surface.Color(0));
			surface.HLine(x, surface.Height() - 1, width, surface.Color(0));
		}
		x += width;

		surface.VLine(x, 0, surface.Height(), surface.Color(0));
		++x;

		it->endX = x;
	}

	surface.FillRect(x, 0, surface.Width() - x, surface.Height() - 1, surface.Color(224));
	surface.HLine(x, surface.Height() - 1, surface.Width() - x, surface.Color(0));
	surface.HLine(x, 0, surface.Width() - x, surface.Color(0));
}



void TabView::ActivateView(Interface *gui)
{
	if(!gui)
		gui = GetInterface();
	if(gui)
	{
		gui->BringToFront(active->view);
		gui->BringToFront(this);
	}
}
